home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / nntpcli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  22.0 KB  |  868 lines

  1.  
  2. /*   Client routines for Network News Tranfer Protocol ala RFC977  */
  3.  
  4. #include <stdio.h>
  5. #include <exec/types.h>
  6. #include <time.h>
  7. #include <ctype.h>
  8. #include <string.h>  /* for strchr() */
  9. #include "global.h"
  10. #include "timer.h"
  11. #include "cmdparse.h"
  12. #include "commands.h"
  13. #include "socket.h"
  14. #include "usock.h"
  15. #include "netuser.h"
  16. #include "proc.h"
  17. #include "smtp.h"
  18. #include "files.h"
  19. #include "session.h"
  20. #include "dirutil.h"
  21. #include "amiga/stat.h"
  22.  
  23. #define NNTPMAXLEN   512
  24.  
  25. static struct nntpservers {
  26.    struct timer nntpcli_t;
  27.    char *name;
  28.    int lowtime, hightime;  /* for connect window */
  29.    struct nntpservers *next;
  30. };
  31.  
  32. #define   NULLNNTP   (struct nntpservers *)NULL
  33.  
  34. struct nntpservers *Nntpservers = NULLNNTP;
  35. static unsigned short nntptrace = 1;
  36. char respbuf[NNTPMAXLEN];
  37.  
  38. static void nntptick __ARGS((void *tp));
  39. static void nntp_job __ARGS((int i1,void *tp,void *v1));
  40. static int gettxt __ARGS((int s,FILE *fp));
  41. static int getreply __ARGS((int s));
  42. static int getarticle __ARGS((int s,long msgid,char *mygroup));
  43. static int doadds __ARGS((int argc,char *argv[],void *p));
  44. static int dodrops __ARGS((int argc,char *argv[],void *p));
  45. static int dokicks __ARGS((int argc,char *argv[],void *p));
  46. static int dolists __ARGS((int argc,char *argv[],void *p));
  47. static int donntrace __ARGS((int argc,char *argv[],void *p));
  48.  
  49. static int donnprofile __ARGS((int argc,char *argv[],void *p));
  50. static int donnfull __ARGS((int argc,char *argv[],void *p));
  51. static int donnhost __ARGS((int argc,char *argv[],void *p));
  52. static int donnorgan __ARGS((int argc,char *argv[],void *p));
  53. static int donnreply __ARGS((int argc,char *argv[],void *p));
  54. static int donnsig __ARGS((int argc,char *argv[],void *p));
  55. static int donnuser __ARGS((int argc,char *argv[],void *p));
  56. static int donnpost __ARGS((int argc,char *argv[],void *p));
  57. static int check_blank __ARGS((char *bp));
  58. static int donntplist __ARGS((int argc,char *argv[],void *p));
  59. static int donntpkill __ARGS((int argc,char *argv[],void *p));
  60.  
  61. static char *Puser     = NULLCHAR;
  62. static char *Preply    = NULLCHAR;
  63. static char *Psig      = NULLCHAR;
  64. static char *Porgan    = NULLCHAR;
  65. static char *Pfullname = NULLCHAR;
  66. static char *Host      = NULLCHAR;
  67.  
  68. /* Tracing levels:
  69.    0 - no tracing
  70.    1 - serious errors reported
  71.    2 - transient errors reported
  72.    3 - session progress reported
  73.    4 - actual received articles displayed
  74.  */
  75.  
  76. static struct cmds Nntpcmds[] = {
  77.    "addserver",   doadds,      0, 3, "nntp addserver <nntpserver> <interval>",
  78.    "dropserver",  dodrops,     0, 2, "nntp dropserver <nntpserver>",
  79.    "kick",        dokicks,     0, 2, "nntp kick <nntpserver>",
  80.    "kill",        donntpkill,  0, 2, "nntp kill <jobnumber>",
  81.    "listservers", dolists,     0, 0, NULLCHAR,
  82.    "messages",    donntplist,  0, 0, NULLCHAR,
  83.    "profile",     donnprofile, 0, 0, NULLCHAR,
  84.    "post",        donnpost,    2024, 0, NULLCHAR,
  85.    "trace",       donntrace,   0, 0, NULLCHAR,
  86.    NULLCHAR,
  87. };
  88.  
  89. int donntp(argc,argv,p)
  90. int argc;
  91. char *argv[];
  92. void *p;
  93. {
  94.    if(argc == 1)
  95.       return donntplist(argc,argv,p);
  96.    return subcmd(Nntpcmds,argc,argv,p);
  97. }
  98.  
  99. static int doadds(argc,argv,p)
  100. int argc;
  101. char *argv[];
  102. void *p;
  103. {
  104.    struct nntpservers *np;
  105.    for(np = Nntpservers; np != NULLNNTP; np = np->next)
  106.       if(stricmp(np->name,argv[1]) == 0)
  107.          break;
  108.    if (np == NULLNNTP) {
  109.       np = (struct nntpservers *) callocw(1,sizeof(struct nntpservers));
  110.       np->name = strdup(argv[1]);
  111.       np->next = Nntpservers;
  112.       Nntpservers = np;
  113.       np->lowtime = np->hightime = -1;
  114.       np->nntpcli_t.func = nntptick;   /* what to call on timeout */
  115.       np->nntpcli_t.arg = (void *)np;
  116.    }
  117.    if (argc > 3) {
  118.       int i;
  119.       for (i = 3; i < argc; ++i) 
  120.          if (isdigit(*argv[i])) {
  121.             int lh, ll, hh, hl;
  122.             sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  123.             np->lowtime = lh * 100 + ll;
  124.             np->hightime = hh * 100 + hl;
  125.          }
  126.    }
  127.    /* set timer duration */
  128.    np->nntpcli_t.start = atol(argv[2])*(1000/MSPTICK);
  129.    start_timer(&np->nntpcli_t);      /* and fire it up */
  130.    return 0;
  131. }
  132.  
  133. static int dodrops(argc,argv,p)
  134. int argc;
  135. char *argv[];
  136. void *p;
  137. {
  138.    struct nntpservers *np, *npprev = NULLNNTP;
  139.    for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
  140.       if(stricmp(np->name,argv[1]) == 0) {
  141.          stop_timer(&np->nntpcli_t);
  142.          free(np->name);
  143.          if(npprev != NULLNNTP)
  144.             npprev->next = np->next;
  145.          else
  146.             Nntpservers = np->next;
  147.          free((char *)np);
  148.          return 0;
  149.    }
  150.    tprintf("No such server enabled.\n");
  151.    return 0;
  152. }
  153.  
  154. static int dolists(argc,argv,p)
  155. int argc;
  156. char *argv[];
  157. void *p;
  158. {
  159.    struct nntpservers *np;
  160.    for(np = Nntpservers; np != NULLNNTP; np = np->next) {
  161.       char tbuf[80];
  162.       if (np->lowtime != -1 && np->hightime != -1)
  163.          sprintf(tbuf, " -- %02d:%02d-%02d:%02d", np->lowtime/100, np->lowtime%100, np->hightime/100, np->hightime%100);
  164.       else
  165.          tbuf[0] = '\0';
  166.       tprintf("%-32s (%lu/%lu)\n", np->name,
  167.          read_timer(&np->nntpcli_t) * MSPTICK/1000,
  168.          dur_timer(&np->nntpcli_t) * MSPTICK/1000);
  169.    }
  170.    return 0;
  171. }
  172.  
  173. static int donntrace(argc, argv, p)
  174. int argc;
  175. char *argv[];
  176. void *p;
  177. {
  178.    return setshort(&nntptrace,"NNTP tracing",argc,argv);
  179. }
  180.  
  181. static int np_all = 0;  /* non-zero if Newsdir is a malloc'ed space */
  182.  
  183.   
  184. static int dokicks(argc,argv,p)
  185. int argc;
  186. char *argv[];
  187. void *p;
  188. {
  189.    struct nntpservers *np;
  190.    for(np = Nntpservers; np != NULLNNTP; np = np->next)
  191.       if(stricmp(np->name,argv[1]) == 0) {
  192.          /* If the timer is not running, the timeout function has
  193.          * already been called and we don't want to call it again.
  194.          */
  195.          if(run_timer(&np->nntpcli_t)) {
  196.             stop_timer(&np->nntpcli_t);
  197.             nntptick((void *)np);
  198.          }
  199.          return 0;
  200.    }
  201.    tprintf("No such server enabled.\n");
  202.    return 0;
  203. }
  204.  
  205. /* This is the routine that gets called every so often to connect to
  206.  * NNTP servers.
  207.  */
  208. static void nntptick(tp)
  209. void *tp;
  210. {
  211.    newproc("NNTP client", 3072, nntp_job, 0, tp, NULL);
  212. }
  213.  
  214. static void nntp_job(i1,tp,v1)
  215. int i1;
  216. void *tp, *v1;
  217. {
  218.    FILE *wfile, *tfile, *xfile;
  219.    char *cp, *cp1,
  220.       wfilename[13], nnfix[9], xtmp[LINELEN], wtmp[LINELEN],
  221.       ttmp[LINELEN], wgroup[80], mygroup[80], wmsgid[80];
  222.    int s, i, code, now;
  223.    long articles, first, last, mylast;
  224.    struct tm *ltm;
  225.    time_t t;
  226.    struct nntpservers *np = (struct nntpservers *) tp;
  227.    struct sockaddr_in fsocket;
  228.  
  229.    if (nntptrace >= 2)
  230.       mainlog(-1,"NNTP Checking NewsGroups on \"%s\"",np->name);
  231.    if(availmem() < Memthresh){
  232.       if (nntptrace >= 2)
  233.          mainlog(-1,"NNTP daemon quit -- low memory");
  234.       /* Memory is tight, don't do anything */
  235.       start_timer(&np->nntpcli_t);
  236.       return;
  237.    }
  238.  
  239.    time(&t);   /* more portable than gettime() */
  240.    ltm = localtime(&t);
  241.    now = ltm->tm_hour * 100 + ltm->tm_min;
  242.    if (np->lowtime < np->hightime) {  /* doesn't cross midnight */
  243.       if (now < np->lowtime || now >= np->hightime) {
  244.          if (nntptrace >= 3)
  245.             mainlog(-1,"NNTP window to '%s' not open", np->name);
  246.          start_timer(&np->nntpcli_t);
  247.          return;
  248.       }
  249.    } else {
  250.       if (now < np->lowtime && now >= np->hightime) {
  251.          if (nntptrace >= 3)
  252.             mainlog(-1,"NNTP window to '%s' not open", np->name);
  253.          start_timer(&np->nntpcli_t);
  254.          return;
  255.       }
  256.    }
  257.  
  258.    fsocket.sin_addr.s_addr = resolve(np->name);
  259.    if(fsocket.sin_addr.s_addr == 0) {  /* No IP address found */
  260.       if (nntptrace >= 2)
  261.          mainlog(-1,"NNTP can't resolve host \"%s\"", np->name);
  262.       /* Try again later */
  263.       start_timer(&np->nntpcli_t);
  264.       return;
  265.    }
  266.    fsocket.sin_family = AF_INET;
  267.    fsocket.sin_port = IPPORT_NNTP; 
  268.  
  269.    s = socket(AF_INET,SOCK_STREAM,0);
  270.    /* sockmode(s,SOCK_ASCII); */
  271.    if(connect(s,(char *)&fsocket,SOCKSIZE) == -1){
  272.       cp = sockerr(s);
  273.       mainlog(-1,"NNTP %s Connect failed: %s",psocket(&fsocket),
  274.          cp != NULLCHAR ? cp : "");
  275.       goto quit;
  276.    }
  277.    /* Eat the banner */
  278.    i = getreply(s);
  279.    if(i >= 400) {
  280.       mainlog(-1,"NNTP %s bad reply on banner (response was %d)",psocket(&fsocket),i);
  281.       goto quit;
  282.    }
  283.  
  284.    if(i == 201) {
  285.       if (nntptrace >= 1)
  286.          mainlog(-1,"NNTP - No posting allowed on \"%s\"", np->name);
  287.    } else {
  288.       for(filedir(Newsqueue,0,wfilename); wfilename[0] != '\0';
  289.          filedir(Newsqueue,1,wfilename)) {
  290.  
  291.          cp = wfilename;
  292.          cp1 = nnfix;
  293.          while (*cp && *cp != '.')
  294.             *cp1++ = *cp++;
  295.          *cp1 = '\0';
  296.  
  297.          sprintf(wtmp,"%s/%s",Newsdir,wfilename);
  298.          if ((wfile = fopen(wtmp,READ_TEXT)) == NULLFILE) 
  299.             continue;
  300.          (void) fgets(wgroup,LINELEN,wfile);      /* read target group */
  301.          rip(wgroup);
  302.          (void) fgets(wmsgid,LINELEN,wfile);      /* read messageid */
  303.          rip(wmsgid);
  304.          fclose(wfile);
  305.  
  306.          if (nntptrace >= 3)
  307.             mainlog(-1,"==>GROUP %s", wgroup);
  308.          usprintf(s,"GROUP %s\n", wgroup);
  309.          i = getreply(s);
  310.          if(i == 411) {
  311.             if (nntptrace >= 1)
  312.                mainlog(-1,"NNTP No Such Newsgroup '%s'",wgroup);
  313.             continue;
  314.          }
  315.          if(i == 211) {
  316.             if (nntptrace >= 3)
  317.                mainlog(-1,"==>POST");
  318.             usprintf(s,"POST\n");
  319.             i = getreply(s);
  320.             if(i == 340) { /* Send It */
  321.                sprintf(ttmp,"%s/%s.txt", Newsdir, nnfix);
  322.                if((tfile = fopen(ttmp, READ_TEXT)) != NULLFILE) {
  323.                   while(fgets(ttmp, LINELEN, tfile) != NULLCHAR)
  324.                      usprintf(s,ttmp);
  325.                   fclose(tfile);
  326.                }
  327.                i = getreply(s);
  328.                if(i == 240)
  329.                   remove(wtmp);
  330.             }
  331.             if(i == 440)
  332.                if (nntptrace >= 1)
  333.                   mainlog(-1,"NNTP Posting not allowed");
  334.             if(i == 441)
  335.                if (nntptrace >= 1)
  336.                   mainlog(-1,"NNTP Transfer failed");
  337.          }
  338.       }
  339.    }
  340.  
  341. /*=============== COLLECT NEWS (testing !) =====================*/
  342.    sprintf(wtmp,"%s/Groups",Newsdir);
  343.    if ((wfile = fopen(wtmp,READ_TEXT)) == NULLFILE) {
  344.       if (nntptrace >= 1)
  345.          mainlog(-1,"NNTP NewsGroup Control file not found");
  346.       goto quit;
  347.    }
  348.  
  349.    sprintf(xtmp,"%s/Groups.New",Newsdir);
  350.    if ((xfile = fopen(xtmp,WRITE_TEXT)) == NULLFILE) {
  351.       if (nntptrace >= 1)
  352.          mainlog(-1,"NNTP Unable to open Backup NewsGroup file");
  353.       goto quit;
  354.    }
  355.  
  356.    while (fgets(wgroup,LINELEN,wfile) != NULLCHAR) {      /* read target group */
  357.       rip(wgroup);
  358.       sscanf(wgroup,"%ld %s", &mylast, &mygroup);
  359.       if (mygroup == NULLCHAR)
  360.          goto quit;
  361.  
  362.       if (nntptrace >= 3)
  363.          mainlog(-1,"==>GROUP %s", mygroup);
  364.       usprintf(s,"GROUP %s\n", mygroup);
  365.       i = getreply(s);
  366.  
  367.       if(i == 411) {
  368.          if (nntptrace >= 1)
  369.             mainlog(-1,"NNTP No Such Newsgroup '%s'",mygroup);
  370.          continue;
  371.       }
  372.       if(i == 211) {
  373.          sscanf(respbuf,"%d %ld %ld %ld ", &code, &articles, &first, &last);
  374.  
  375.          mainlog(-1, "First ( %ld ) - Last ( %ld ) - MyLast ( %ld )",
  376.                      first, last, mylast);
  377.  
  378.          if(mylast<=first) mylast=--first;
  379.  
  380.          while (++mylast <= last) {
  381.             mainlog(-1,"NNTP Retrieving '%ld'", mylast);
  382.             if(getarticle(s,mylast,mygroup) == -1)
  383.                mainlog(-1,"NNTP Gave up with article '%ld'", mylast);
  384.          }
  385.       }
  386.  
  387.       fprintf(xfile,"%ld %s\n", --mylast, mygroup);
  388.  
  389.       continue;
  390.    }
  391.  
  392. quit:
  393.    if (nntptrace >= 3)
  394.       mainlog(-1,"==>QUIT");
  395.    usprintf(s,"QUIT\n");
  396.    /* Eat the response */
  397.    getreply(s);
  398.    if (nntptrace >= 2)
  399.       mainlog(-1,"NNTP Finished with \"%s\"", np->name);
  400.    close_s(s);
  401.  
  402.    fclose(wfile);
  403.    fclose(xfile);
  404.  
  405.    unlink(wtmp);
  406.    rename(xtmp,wtmp);
  407.  
  408.    /* Restart timer */
  409.    start_timer(&np->nntpcli_t);
  410.  
  411.    return;
  412. }
  413.  
  414. static int gettxt(s,fp)
  415. int s;
  416. FILE *fp;
  417. {
  418.    char buf[NNTPMAXLEN];
  419.    int nlines;
  420.  
  421.    for (nlines = 0; recvline(s,buf,NNTPMAXLEN) != -1; ++nlines) {
  422.       if(strcmp(buf,".\n") == 0) {
  423.          if (nntptrace >= 3)
  424.             mainlog(-1,"NNTP received %d lines", nlines);
  425.          return 0;
  426.          }
  427.       /* check for escaped '.' characters */
  428.       if(strcmp(buf,"..\n") == 0)
  429.          fputs(".\n",fp);
  430.       else
  431.          fputs(buf,fp);
  432.       if (nntptrace >= 4) {
  433.          rip(buf); /* so that the log entries don't have an extra CR */
  434.          mainlog(-1,"<==%s", buf);
  435.       }
  436.    }
  437.    if (nntptrace >= 1)
  438.       mainlog(-1,"NNTP receive error after %d lines", nlines);
  439.    return -1;
  440. }
  441.  
  442. static int getreply(s)
  443. int s;
  444. {
  445.    int response;
  446.  
  447.    while(recvline(s,respbuf,NNTPMAXLEN) != -1) {
  448.       /* skip informative messages and blank lines */
  449.       if(respbuf[0] == '\0' || respbuf[0] == '1' || respbuf[0] == '5')
  450.          continue;
  451.       rip(respbuf);
  452.       sscanf(respbuf,"%d",&response);
  453.       if (nntptrace >= 3)
  454.          mainlog(-1,"<==%s", respbuf);
  455.       return response;
  456.    }
  457.    if (nntptrace >= 3)
  458.       mainlog(-1,"==No response");
  459.    return -1;
  460. }
  461.  
  462. static int getarticle(s,msgid,mygroup)
  463. int s;
  464. long msgid;
  465. char *mygroup;
  466. {
  467.    char buf[NNTPMAXLEN], froml[NNTPMAXLEN], *cp;
  468.    FILE *fp, *tmpf;
  469.    int i;
  470.  
  471.    if (nntptrace >= 3)
  472.       mainlog(-1,"==>ARTICLE %ld", msgid);
  473.    usprintf(s,"ARTICLE %ld\n", msgid);
  474.    i = getreply(s);
  475.  
  476.    if(i == -1 || i >= 500)
  477.       return -1;
  478.    if(i >= 400)
  479.       return 0;
  480.  
  481.    if((tmpf = tmpfile()) == NULLFILE) {
  482.       if (nntptrace >= 1)
  483.          mainlog(-1,"NNTP Cannot open temp file for article");
  484.       return -1;
  485.    }
  486.    if(gettxt(s,tmpf) == -1) {
  487.       fclose(tmpf);
  488.       return -1;
  489.    }
  490.  
  491.    /* convert the article into mail format */
  492.    rewind(tmpf);
  493.    froml[0] = '\0';
  494.    while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  495.       if(strncmp(buf,"From: ",6) == 0) {
  496.          time_t t;
  497.          rip(&buf[6]);
  498.          time(&t);
  499.          sprintf(froml,"From %s %s",&buf[6], ctime(&t));
  500.       }
  501.       /* invalid article - missing 'From:' line */
  502.       if(strcmp(buf,"\n") == 0 && froml[0] == '\0' ) {
  503.          fclose(tmpf);
  504.          break;
  505.       }
  506.    }
  507.  
  508.    sprintf(buf, "%s/%s", Mailspool,  mygroup);
  509.  
  510. /* This bit is supposed to create a directory chain and then tag .txt  */
  511. /* on to the end , i.e xx.yy.zz becomes xx/yy/zz.txt                   */
  512.    for(cp = buf;*cp != '\0';cp++)
  513.       if (*cp == '.' ) {
  514.          *cp = '\0';
  515.          mkdir(buf);
  516.          *cp = '/';
  517.    }
  518.    strcat(buf, ".txt");
  519. /* ------------------------------------------------------------------- */
  520.  
  521.    /* open the mail file */
  522.    printf("Writing article to '%s'\n", buf);
  523.    if((fp = fopen(buf,APPEND_TEXT)) != NULLFILE) {
  524.       fputs(froml,fp);
  525.       rewind(tmpf);
  526.       while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  527.          /* for UNIX mail compatiblity */
  528.          if(strncmp(buf,"From ",5) == 0)
  529.             putc('>',fp);
  530.          fputs(buf,fp);
  531.       }
  532.       putc('\n',fp);
  533.       fclose(fp);
  534.    }
  535.  
  536.    fclose(tmpf);
  537.  
  538.    return 0;
  539. }
  540.  
  541. /* -------------------- Profile subcmds -------------------- */
  542.  
  543. static int donnuser(argc,argv,p)
  544. int argc;
  545. char *argv[];
  546. void *p;
  547. {
  548.    if(argc < 2)
  549.       tprintf("%s\n",Puser);
  550.    else {
  551.       free(Puser);
  552.       Puser = strdup(argv[1]);
  553.    }
  554.    return 0;
  555. }
  556.  
  557. static int donnsig(argc,argv,p)
  558. int argc;
  559. char *argv[];
  560. void *p;
  561. {
  562.    if(argc < 2)
  563.       tprintf("%s\n",Psig);
  564.    else {
  565.       if(access(argv[1],0) == 0) {
  566.          free(Psig);
  567.          Psig = strdup(argv[1]);
  568.       } else {
  569.          tputs("No such signature file\n");
  570.          return -1;
  571.       }
  572.    }
  573.    return 0;
  574. }
  575.  
  576. static int donnfull(argc,argv,p)
  577. int argc;
  578. char *argv[];
  579. void *p;
  580. {
  581.    if(argc < 2)
  582.       tprintf("%s\n",Pfullname);
  583.    else {
  584.       free(Pfullname);
  585.       Pfullname = strdup(argv[1]);
  586.    }
  587.    return 0;
  588. }
  589.  
  590. static int donnhost(argc,argv,p)
  591. int argc;
  592. char *argv[];
  593. void *p;
  594. {
  595.    if(argc < 2)
  596.       tprintf("%s\n",Host);
  597.    else {
  598.       free(Host);
  599.       Host = strdup(argv[1]);
  600.    }
  601.    return 0;
  602. }
  603.  
  604. static int donnorgan(argc,argv,p)
  605. int argc;
  606. char *argv[];
  607. void *p;
  608. {
  609.    if(argc < 2)
  610.       tprintf("%s\n",Porgan);
  611.    else {
  612.       free(Porgan);
  613.       Porgan = strdup(argv[1]);
  614.    }
  615.    return 0;
  616. }
  617.  
  618. static int donnreply(argc,argv,p)
  619. int argc;
  620. char *argv[];
  621. void *p;
  622. {
  623.    if(argc < 2)
  624.       tprintf("%s\n",Preply);
  625.    else {
  626.       free(Preply);
  627.       Preply = strdup(argv[1]);
  628.    }
  629.    return 0;
  630. }
  631.  
  632. struct cmds Prof[] = {
  633.    "fullname",   donnfull,    0, 0, NULLCHAR,
  634.    "host",       donnhost,    0, 0, NULLCHAR,
  635.    "organ",      donnorgan,   0, 0, NULLCHAR,
  636.    "reply",      donnreply,   0, 0, NULLCHAR,
  637.    "sig",        donnsig,     0, 0, NULLCHAR,
  638.    "user",       donnuser,    0, 0, NULLCHAR,
  639.    NULLCHAR,
  640. };
  641.  
  642. /* subcmd parser */
  643. static int donnprofile(argc,argv,p)
  644. int argc;
  645. char *argv[];
  646. void *p;
  647. {
  648.    if(argc == 1) {
  649.       if (Host == NULLCHAR) {
  650.          Host = strdup(Hostname);
  651.       }
  652.  
  653.       if (Host != NULLCHAR)
  654.          tprintf("Hostname     : %s\n",Host);
  655.       if (Pfullname != NULLCHAR)
  656.          tprintf("Full Name    : %s\n",Pfullname);
  657.       if (Porgan != NULLCHAR)
  658.          tprintf("Organisation : %s\n",Porgan);
  659.       if (Preply != NULLCHAR)
  660.          tprintf("Reply-To     : %s\n",Preply);
  661.       if (Psig != NULLCHAR)
  662.          tprintf("Signature    : %s\n",Psig);
  663.       if (Puser != NULLCHAR)
  664.          tprintf("User Name    : %s\n",Puser);
  665.  
  666.       return 0;
  667.    }
  668.    return subcmd(Prof,argc,argv,p);
  669. }
  670.  
  671. /* manually entering new news
  672.  * returncode: -1 if error; 0 success */
  673. static int donnpost(argc,argv,p)
  674. int argc;
  675. char *argv[];
  676. void *p;
  677. {
  678.    struct session *sp;
  679.    char buf[NNTPMAXLEN], pbuf[80], qbuf[80];
  680.    int id;
  681.    long currtime;
  682.    FILE *idf, *ufp, *fp, *fq;
  683.  
  684.    if((sp = newsession("Post",POST,0)) == NULLSESSION) {
  685.       tprintf("Too many sessions\n");
  686.       freeargs(argc,argv);
  687.       return 1;
  688.    }
  689.  
  690.    for (;;) {
  691.       id = get_msgid();
  692.  
  693.       sprintf(pbuf,"%s/%d.txt",Newsdir,id);
  694.       fp = fopen(pbuf,WRITE_TEXT);
  695.       sprintf(qbuf,"%s/%d.wrk",Newsdir,id);
  696.       fq = fopen(qbuf,WRITE_TEXT);
  697.  
  698.       if (Puser == NULLCHAR) {
  699.          tprintf("User name? ");
  700.          recvline(sp->input,buf,NNTPMAXLEN);
  701.          rip(buf);
  702.          if (check_blank(buf)) {
  703.             fclose(fp);
  704.             fclose(fq);
  705.             remove(pbuf);
  706.             remove(qbuf);
  707.             goto done;
  708.          }
  709.          Puser = strdup(buf);
  710.       }
  711.  
  712.       fprintf(fp,"Path: %s\n",Host);
  713.       fprintf(fp,"From: %s@%s",Puser,Hostname);
  714.  
  715.       if (Pfullname != NULLCHAR)
  716.          fprintf(fp," (%s )",Pfullname);
  717.       fprintf(fp,"\n");
  718.  
  719.       tprintf("Newsgroup? ");
  720.       recvline(sp->input,buf,NNTPMAXLEN);
  721.       rip(buf);
  722.       if (check_blank(buf)) {
  723.          fclose(fp);
  724.          fclose(fq);
  725.          remove(pbuf);
  726.          remove(qbuf);
  727.          goto done;
  728.       }
  729.       fprintf(fp,"Newsgroups: %s\n",buf);
  730.       fprintf(fq,"%s\n",buf);
  731.  
  732.       tprintf("Subject? ");
  733.       recvline(sp->input,buf,NNTPMAXLEN);
  734.       rip(buf);
  735.       if (!check_blank(buf))
  736.          fprintf(fp,"Subject: %s\n",buf);
  737.       fprintf(fp,"Message-Id: <%d@%s>\n",id,Hostname);
  738.       fprintf(fq,"<%d@%s>\n",id,Hostname);
  739.       time(&currtime);
  740.       fprintf(fp,"Date: %s",ptime(&currtime));
  741.       fprintf(fp,"Sender: NNTP@%s\n",Hostname);
  742.  
  743.       if (Preply != NULLCHAR)
  744.          fprintf(fp,"Reply-To: %s\n",Preply);
  745.  
  746.       if (Porgan != NULLCHAR)
  747.          fprintf(fp,"Organization: %s\n",Porgan);
  748.  
  749.       fprintf(fp, "Comment: AmigaNOS v%s\n", Version);
  750.  
  751.       fprintf(fp,"\n");
  752.       tputs("Enter message - end with . or /EX ('.r' or '.u' to upload)\n");
  753.  
  754.       for (;;) {
  755.          recvline(sp->input,buf,NNTPMAXLEN);
  756.          if(strcmp(buf,".u\n") == 0 || strcmp(buf,".r\n") == 0) {
  757.             tputs("Filename? ");
  758.             recvline(sp->input, buf, LINELEN);
  759.             rip(buf);
  760.             if((ufp = fopen(buf, READ_TEXT)) != NULLFILE) {
  761.                while(fgets(buf, NNTPMAXLEN, ufp) != NULL)
  762.                   fputs(buf, fp);
  763.                fclose(ufp);
  764.             }
  765.             tputs("(continue)\n");
  766.          }
  767.          if(strcmp(buf,".\n") == 0 || 
  768.             strcmpi(buf,"***END\n") == 0 || 
  769.             strcmpi(buf,"/EX\n") == 0)
  770.             break;
  771.          fprintf(fp,"%s",buf);
  772.       }
  773.  
  774.       if (Psig != NULLCHAR) {
  775.          sprintf(buf,"%s",Psig);
  776.          if ((idf = fopen(buf,READ_TEXT)) != NULLFILE ) {
  777.             while(fgets(buf,NNTPMAXLEN,idf) != NULL)
  778.                fprintf(fp,"%s",buf);
  779.             fclose(idf);
  780.          }
  781.       }
  782.  
  783. loop:
  784.       fprintf(fp,"\n.\n");
  785.  
  786.       fclose(fp);
  787.       fclose(fq);
  788.  
  789.       tprintf("Post another? ");
  790.       recvline(sp->input,buf,NNTPMAXLEN);
  791.       if (tolower(buf[0]) == 'n')
  792.          goto done;
  793.    }
  794.  
  795. done:
  796.    freesession(sp);
  797.    return 0;
  798. }
  799.  
  800. /* checks for not valid chars in a line
  801.  * returncode: 0 if valid; 1 if invalid */
  802. static int check_blank(bp)
  803. char *bp;
  804. {
  805.    if (strpbrk(bp, "!@#$%^&*()_+=<>,./?~`[]{}\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
  806.       return 1;
  807.    return 0;
  808. }
  809.  
  810. /* list messages wating to be sent */
  811. static int donntplist(argc,argv,p)
  812. int argc;
  813. char *argv[];
  814. void *p;
  815. {
  816.    char tstring[80], line[20],
  817.         group[LINELEN], *cp;
  818.    struct stat stbuf;
  819.    struct tm *tminfo, *localtime();
  820.    FILE *fp;
  821.  
  822.    Current->flowmode = 1;          /* Enable the more mechanism */
  823.    tprintf("    Job    Size  Date  Time Group\n");
  824.    filedir(Newsqueue,0,line);
  825.    while(line[0] != '\0') {
  826.       sprintf(tstring,"%s/%s",Newsdir,line);
  827.       if ((fp = fopen(tstring,READ_TEXT)) == NULLFILE) {
  828.          tprintf("Can't open %s: %s\n",tstring,sys_errlist[errno]);
  829.          continue;
  830.       }
  831.       if ((cp = strrchr(line,'.')) != NULLCHAR)
  832.          *cp = '\0';
  833.       sprintf(tstring,"%s/%s.txt",Newsdir,line);
  834.       stat(tstring,&stbuf);
  835.       tminfo = localtime(&stbuf.st_ctime);
  836.       fgets(group,sizeof(group),fp);
  837.       rip(group);
  838.       tprintf("%7s %7ld %02d/%02d %02d:%02d %-25s\n",
  839.          line, stbuf.st_size,
  840.          tminfo->tm_mon+1, tminfo->tm_mday, tminfo->tm_hour,
  841.          tminfo->tm_min, group);
  842.       (void) fclose(fp);
  843.       pwait(NULL);
  844.       filedir(Newsqueue,1,line);
  845.    }
  846.    Current->flowmode = 0;
  847.    return 0;
  848. }
  849.  
  850. /* kill a job in the mqueue */
  851. static int donntpkill(argc,argv,p)
  852. int argc;
  853. char *argv[];
  854. void *p;
  855. {
  856.    char s[LINELEN];
  857.    char *cp;
  858.  
  859.    sprintf(s,"%s/%s.wrk",Newsdir,argv[1]);
  860.    cp = strrchr(s,'.');
  861.    if (remove(s))
  862.       tprintf("Job id %s not found\n",argv[1]);
  863.    strcpy(cp,".txt");
  864.    (void) remove(s);
  865.    return 0;
  866. }
  867.  
  868.